#ifndef XLCOMM_BASE_LOGGER_H_
#define XLCOMM_BASE_LOGGER_H_

#include <errno.h>
#include <string.h>

#include "xlcomm/base/current_thread.h"
#include "xlcomm/base/log_stream.h"
#include "xlcomm/base/string_piece.h"
#include "xlcomm/define.h"
#include "xlcomm/noncopyable.h"

namespace xlcomm {

// 日志记录类
class XLCOMM_API Logger : noncopyable {
 public:
  using OutputFunc = void (*)(const char* msg, size_t len);
  using FlushFunc = void (*)(void);

  // 日志级别
  enum LogLevel { kTrace, kDebug, kInfo, kWarn, kError, kFatal };

  explicit Logger(LogLevel cur_level, const char* source_path = "",
                  int line = 0, const char* func_name = "");
  ~Logger();

  // 获取stream引用
  LogStream& stream() { return stream_; }

  // 设置日志最终的输出函数
  static void SetOutputFunc(OutputFunc output_func);

  // 设置清空缓冲区函数
  static void SetFlushFunc(FlushFunc flush_func);

  // 设置日志内容写到文件
  // @param file_name 基础文件名
  // @param sync      是否同步写
  static void SetWriteToFile(const char* file_name, bool sync = true);

  // 设置日志输出级别
  static void SetLogLevel(LogLevel log_level);

  // 获取日志输出级别
  static LogLevel GetLogLevel();

 private:
  // 完成一次输出
  void Finish();

  LogStream stream_;
  LogLevel cur_level_;
  StringPiece source_file_;
  int line_;
  const char* func_name_;
};

const char* strerror_tl(int saved_errno);

//
// [CAUTION] do not write:
//
// if (good)
//   LOG_INFO << "Good news";
// else
//   LOG_WARN << "Bad news";
//
// this expends to:
//
// if (good)
//   if (log_level)
//     log_info_stream << "Good news";
//   else
//     log_warn_stream << "Bad news";
//
// should write:
//
// if (good) {
//   LOG_INFO << "Good news";
// } else {
//   LOG_WARN << "Bad news";
// }

#define LOG_TRACE                                                          \
  if (xlcomm::Logger::GetLogLevel() <= xlcomm::Logger::kTrace)             \
  xlcomm::Logger(xlcomm::Logger::kTrace, __FILE__, __LINE__, __FUNCTION__) \
      .stream()

#define LOG_DEBUG                                              \
  if (xlcomm::Logger::GetLogLevel() <= xlcomm::Logger::kDebug) \
  xlcomm::Logger(xlcomm::Logger::kDebug, __FILE__, __LINE__).stream()

#define LOG_INFO                                              \
  if (xlcomm::Logger::GetLogLevel() <= xlcomm::Logger::kInfo) \
  xlcomm::Logger(xlcomm::Logger::kInfo, __FILE__, __LINE__).stream()

#define LOG_WARN                                                          \
  if (xlcomm::Logger::GetLogLevel() <= xlcomm::Logger::kWarn)             \
  xlcomm::Logger(xlcomm::Logger::kWarn, __FILE__, __LINE__, __FUNCTION__) \
      .stream()

#define LOG_ERROR                                                          \
  xlcomm::Logger(xlcomm::Logger::kError, __FILE__, __LINE__, __FUNCTION__) \
      .stream()

// 致命错误，退出程序。一些程序无法进行下去的错误可以使用
#define LOG_FATAL                                                          \
  xlcomm::Logger(xlcomm::Logger::kFatal, __FILE__, __LINE__, __FUNCTION__) \
      .stream()

// 系统调用错误（附errno全局错误码和错误信息）
#define LOG_SYSERROR(func_name)                         \
  LOG_ERROR << "::" << #func_name << " error(" << errno \
            << "):" << strerror_tl(errno) << "! "

// 系统调用致命错误，退出程序（附errno全局错误码和错误信息）
#define LOG_SYSFATAL(func_name)                         \
  LOG_FATAL << "::" << #func_name << " error(" << errno \
            << "):" << strerror_tl(errno) << "! "

// 通用断言
#define XLCOMM_ASSERT(expression)                                   \
  {                                                                 \
    if (!(expression)) {                                            \
      LOG_FATAL << "XLCOMM_ASSERT(" << #expression << ") failure! " \
                << xlcomm::CurrentThread::StackTrace();             \
    }                                                               \
  }

}  // namespace xlcomm

#endif  // XLCOMM_BASE_LOGGER_H_